home *** CD-ROM | disk | FTP | other *** search
- /*
- * LfsStableMem.c --
- *
- * Generic routines for supporting an in memory data structure that
- * is written to a LFS log at each checkpoint. The blocks of the
- * data structures are kept as file in the file cache.
- *
- * Copyright 1989 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/lfs/lfsStableMem.c,v 1.12 92/06/01 15:07:25 kupfer Exp $ SPRITE (Berkeley)";
- #endif /* not lint */
-
- #include <lfsInt.h>
- #include <lfsSeg.h>
- #include <lfsStableMemInt.h>
- #include <stdlib.h>
- #include <fsdm.h>
-
- static Boolean AddBlockToSegment _ARGS_((LfsStableMem *smemPtr,
- Address address, int blockNum, ClientData clientData,
- LfsSeg *segPtr));
- static Boolean BlockMatch _ARGS_((Fscache_Block *blockPtr,
- ClientData clientData));
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemLoad --
- *
- * Allocate and load a LFS stable memory resident data structure.
- *
- * Results:
- * SUCCESS if load succeed ok.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsStableMemLoad(lfsPtr, smemParamsPtr, checkPointSize, checkPointPtr, smemPtr)
- Lfs *lfsPtr; /* File system of metadata. */
- LfsStableMemParams *smemParamsPtr; /* Parameters for this memory. */
- int checkPointSize; /* Size of checkpoint data. */
- char *checkPointPtr; /* Data from last checkpoint before shutdown. */
- LfsStableMem *smemPtr; /* In memeory index data structures. */
- {
- int blockNum, bufferSize;
- LfsStableMemCheckPoint *cpPtr;
- Fscache_Attributes attr;
- static int nextMinorNumber = -1;
-
- cpPtr = (LfsStableMemCheckPoint *) checkPointPtr;
- /*
- * Do some bounds checking on the checkpoint buffer.
- */
- if ((checkPointSize < sizeof(LfsStableMemCheckPoint)) ||
- (checkPointSize < (cpPtr->numBlocks * sizeof(int) +
- sizeof(LfsStableMemCheckPoint)))) {
- return FAILURE;
- }
- /*
- * Fill in the LfsStableMem data structures.
- *
- */
- smemPtr->lfsPtr = lfsPtr;
- /*
- * Initialize the file handle used for storing blocks in the
- * file cache.
- */
-
- bzero((Address)&smemPtr->dataHandle, sizeof(smemPtr->dataHandle));
- smemPtr->dataHandle.hdr.fileID.serverID = rpc_SpriteID;
- smemPtr->dataHandle.hdr.fileID.major = lfsPtr->domainPtr->domainNumber;
- smemPtr->dataHandle.hdr.fileID.minor = nextMinorNumber--;
- smemPtr->dataHandle.hdr.fileID.type = FSIO_LCL_FILE_STREAM;
- smemPtr->dataHandle.hdr.name = "LfsStableMemFile";
- smemPtr->dataHandle.descPtr = (Fsdm_FileDescriptor *)NIL;
-
- bzero((Address)&attr, sizeof(attr));
- attr.lastByte = smemParamsPtr->blockSize * smemParamsPtr->maxNumBlocks;
- Fscache_FileInfoInit(&smemPtr->dataHandle.cacheInfo,
- (Fs_HandleHeader *) &smemPtr->dataHandle,
- 0, TRUE, &attr, lfsPtr->domainPtr->backendPtr);
-
- /*
- * Allocate and copy the index for the metadata.
- */
- bufferSize = smemParamsPtr->maxNumBlocks * sizeof(int);
- smemPtr->blockIndexPtr = (LfsDiskAddr *) malloc(bufferSize);
- bcopy(checkPointPtr + sizeof(LfsStableMemCheckPoint),
- (char *) smemPtr->blockIndexPtr,
- cpPtr->numBlocks * sizeof(LfsDiskAddr));
- for (blockNum = cpPtr->numBlocks; blockNum < smemParamsPtr->maxNumBlocks;
- blockNum++) {
- LfsSetNilDiskAddr(&smemPtr->blockIndexPtr[blockNum]);
- }
-
- smemPtr->numCacheBlocksOut = 0;
- /*
- * Fillin the rest of the LfsStableMem data structure with a copy
- * of the checkPoint and Params data.
- */
-
- smemPtr->checkPoint = *cpPtr;
- smemPtr->params = *smemParamsPtr;
-
- return SUCCESS;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemLoad --
- *
- * Allocate and load a LFS stable memory resident data structure.
- *
- * Results:
- * SUCCESS if load succeed ok.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsStableMemDestory(lfsPtr, smemPtr)
- Lfs *lfsPtr; /* File system of metadata. */
- LfsStableMem *smemPtr; /* In memeory index data structures. */
- {
- Fscache_FileInvalidate(&smemPtr->dataHandle.cacheInfo, 0,
- FSCACHE_LAST_BLOCK);
-
- free((char *) smemPtr->blockIndexPtr);
-
- return SUCCESS;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemClean --
- *
- * Routine to handle cleaning pieces containing data for this module.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * happy for the time being.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsStableMemClean(segPtr, sizePtr, numCacheBlocksPtr, clientDataPtr, smemPtr)
- LfsSeg *segPtr; /* Segment containing data to clean. */
- int *sizePtr;
- int *numCacheBlocksPtr;
- ClientData *clientDataPtr;
- LfsStableMem *smemPtr; /* Index pointer. */
- {
- char *summaryPtr;
- int *blockPtr;
- int numBlocks, block, blockOffset;
- LfsDiskAddr blockAddress;
- ReturnStatus status;
- LfsStableMemEntry entry;
-
- summaryPtr = LfsSegGetSummaryPtr(segPtr);
- numBlocks = LfsSegSummaryBytesLeft(segPtr) / sizeof(int);
- blockPtr = (int *) summaryPtr;
- blockAddress = LfsSegDiskAddress(segPtr, LfsSegGetBufferPtr(segPtr));
- blockOffset = 0;
- /*
- * For each block that hasn't moved already, fetch and release the
- * block marking it as dirty.
- */
- for (block = 0; block < numBlocks; block++) {
- LfsDiskAddr newDiskAddr;
- blockOffset += LfsBytesToBlocks(segPtr->lfsPtr,
- smemPtr->params.blockSize);
- LfsDiskAddrPlusOffset(blockAddress, -blockOffset, &newDiskAddr);
- if (LfsSameDiskAddr(smemPtr->blockIndexPtr[blockPtr[block]],
- newDiskAddr)) {
- int entryNumber = blockPtr[block] * smemPtr->params.entriesPerBlock;
- status = LfsStableMemFetch(smemPtr, entryNumber, 0, &entry);
- if (status != SUCCESS) {
- LfsError(segPtr->lfsPtr, status,"Can't clean metadata block\n");
- }
- LfsStableMemRelease(smemPtr, &entry, TRUE);
- (*sizePtr) += smemPtr->params.blockSize;
- }
- }
- return FALSE;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemCheckpoint --
- *
- * Routine to handle checkpointing of data for this module.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * checkpointed.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsStableMemCheckpoint(segPtr, checkPointPtr, flags, checkPointSizePtr,
- clientDataPtr, smemPtr)
- LfsSeg *segPtr; /* Segment containing data for checkpoint. */
- char *checkPointPtr; /* Buffer to write checkpoint data. */
- int flags; /* Flags. */
- int *checkPointSizePtr; /* Bytes added to the checkpoint area.*/
- ClientData *clientDataPtr;
- LfsStableMem *smemPtr; /* Stable memory description. */
- {
- Boolean full = FALSE;
-
- full = LfsStableMemLayout(segPtr, LFS_CHECKPOINT_LAYOUT,
- clientDataPtr, smemPtr);
- /*
- * If we didn't fill the segment, copy the index to the checkpoint buffer.
- */
- if (!full) {
- *(LfsStableMemCheckPoint *) checkPointPtr = smemPtr->checkPoint;
- bcopy((char *) smemPtr->blockIndexPtr,
- checkPointPtr + sizeof(LfsStableMemCheckPoint),
- sizeof(LfsDiskAddr) * smemPtr->checkPoint.numBlocks);
- *checkPointSizePtr = sizeof(int) * smemPtr->checkPoint.numBlocks +
- sizeof(LfsStableMemCheckPoint);
- LFS_STATS_INC(segPtr->lfsPtr->stats.checkpoint.samples);
- switch (smemPtr->params.memType) {
- case LFS_DESC_MAP_MOD: {
- LFS_STATS_ADD(segPtr->lfsPtr->stats.desc.residentCount,
- smemPtr->dataHandle.cacheInfo.blocksInCache);
- break;
- }
- case LFS_SEG_USAGE_MOD: {
- LFS_STATS_ADD(segPtr->lfsPtr->stats.segusage.residentCount,
- smemPtr->dataHandle.cacheInfo.blocksInCache);
- break;
- }
- }
- }
- return full;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemLayout --
- *
- * Routine to handle writing of data for this module.
- *
- * Results:
- * TRUE if more data needs to be written, FALSE if this module is
- * checkpointed.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- Boolean
- LfsStableMemLayout(segPtr, flags, clientDataPtr, smemPtr)
- LfsSeg *segPtr; /* Segment to place data blocks in. */
- int flags; /* Layout flags. */
- ClientData *clientDataPtr;
- LfsStableMem *smemPtr; /* Stable memory description. */
- {
- Boolean full = FALSE;
- Fscache_FileInfo *cacheInfoPtr;
- Fscache_Block *blockPtr;
- int lastDirtyBlock;
- Boolean fsyncOnly;
-
-
- /*
- * Find and layout all the dirty metadata blocks.
- */
- if (*clientDataPtr == (ClientData) NIL) {
- fsyncOnly = ((flags & LFS_CHECKPOINT_LAYOUT) == 0);
- cacheInfoPtr = Fscache_GetDirtyFile(
- segPtr->lfsPtr->domainPtr->backendPtr,
- fsyncOnly, LfsFileMatch,
- (ClientData) (smemPtr->dataHandle.hdr.fileID.minor));
- if (cacheInfoPtr == (Fscache_FileInfo *) NIL) {
- return FALSE;
- }
- *clientDataPtr = (ClientData) cacheInfoPtr;
- } else {
- cacheInfoPtr = (Fscache_FileInfo *) *clientDataPtr;
- }
-
- while(!full) {
- blockPtr = Fscache_GetDirtyBlock(cacheInfoPtr, BlockMatch,
- (ClientData) 0, &lastDirtyBlock);
- if (blockPtr == (Fscache_Block *) NIL) {
- break;
- }
- full = AddBlockToSegment(smemPtr, blockPtr->blockAddr,
- blockPtr->blockNum, (ClientData) blockPtr, segPtr);
- if (full) {
- Fscache_ReturnDirtyBlock(blockPtr, GEN_EINTR);
- } else {
- smemPtr->numCacheBlocksOut++;
- }
-
- }
- if (!full && (smemPtr->numCacheBlocksOut == 0)) {
- Fscache_ReturnDirtyFile(cacheInfoPtr, FALSE);
- }
- return full;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemWriteDone --
- *
- * Routine to inform this module that a write has finished.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsStableMemWriteDone(segPtr, flags, clientDataPtr, smemPtr)
- LfsSeg *segPtr; /* Segment whose write finishes. */
- int flags; /* Write done flags. */
- ClientData *clientDataPtr;
- LfsStableMem *smemPtr; /* Index description. */
- {
- LfsSegElement *bufferLimitPtr, *bufferPtr = LfsSegGetBufferPtr(segPtr);
- Fscache_Block *blockPtr;
-
- blockPtr = (Fscache_Block *) NIL;
- bufferLimitPtr = bufferPtr + LfsSegSummaryBytesLeft(segPtr) / sizeof(int);
- while (bufferPtr < bufferLimitPtr) {
- blockPtr = (Fscache_Block *) bufferPtr->clientData;
- Fscache_ReturnDirtyBlock(blockPtr, SUCCESS);
- bufferPtr++;
- smemPtr->numCacheBlocksOut--;
- }
- if (smemPtr->numCacheBlocksOut == 0) {
- Fscache_ReturnDirtyFile((Fscache_FileInfo *)(*clientDataPtr), FALSE);
- }
- LfsSegSetBufferPtr(segPtr, bufferPtr);
- }
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemFetch --
- *
- * Routine to fetch a stable memory entry and optionally release
- * a previously fetched entry. This routine fetches the data block
- * from the file cache reading it in if it is not present.
- *
- * Results:
- * SUCCESS if entry is fetch. GEN_INVALID_ARG if entryNumber is not
- * vaild. Other ReturnStatus if disk read fails.
- *
- * Side effects:
- * Cache block fetched. Possibly disk I/O performed.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- LfsStableMemFetch(smemPtr, entryNumber, flags, entryPtr)
- LfsStableMem *smemPtr; /* Index description. */
- int entryNumber; /* Entry number wanted. */
- int flags; /* LFS_STABLE_MEM_MAY_DIRTY | LFS_STABLE_MEM_REL_ENTRY*/
- LfsStableMemEntry *entryPtr; /* IN/OUT: Stable memory entry returned. */
- {
- Fscache_Block *blockPtr;
- Boolean found;
- int blockNum, offset;
- ReturnStatus status = SUCCESS;
- Boolean releaseEntry;
- LfsStableMemBlockHdr *hdrPtr;
-
- releaseEntry = ((flags & LFS_STABLE_MEM_REL_ENTRY) != 0);
- if ((entryNumber < 0) || (entryNumber >= smemPtr->params.maxNumEntries)) {
- if (releaseEntry) {
- LfsStableMemRelease(smemPtr, entryPtr, entryPtr->modified);
- }
- return GEN_INVALID_ARG;
- }
- blockNum = entryNumber / smemPtr->params.entriesPerBlock;
- offset = (entryNumber % smemPtr->params.entriesPerBlock) *
- smemPtr->params.entrySize + sizeof(LfsStableMemBlockHdr);
- blockPtr = (Fscache_Block *) NIL;
- if (releaseEntry) {
- if (entryPtr->blockNum == blockNum) {
- blockPtr = (Fscache_Block *) entryPtr->clientData;
- } else {
- LfsStableMemRelease(smemPtr, entryPtr, entryPtr->modified);
- }
- }
- if (blockPtr == (Fscache_Block *) NIL) {
- Boolean dirtied;
- int cacheFlags;
- /*
- * Fetch the block from the cache reading it in if needed.
- */
- cacheFlags = FSCACHE_DESC_BLOCK|FSCACHE_CANT_BLOCK;
- if (flags & LFS_STABLE_MEM_MAY_DIRTY) {
- cacheFlags |= FSCACHE_IO_IN_PROGRESS;
- }
- switch (smemPtr->params.memType) {
- case LFS_DESC_MAP_MOD: {
- LFS_STATS_INC(smemPtr->lfsPtr->stats.desc.descMapBlockAccess);
- break;
- }
- case LFS_SEG_USAGE_MOD: {
- LFS_STATS_INC(smemPtr->lfsPtr->stats.segusage.segUsageBlockAccess);
- break;
- }
- }
- Fscache_FetchBlock(&smemPtr->dataHandle.cacheInfo, blockNum,
- cacheFlags, &blockPtr, &found);
- dirtied = FALSE;
- if (!found && (blockPtr != (Fscache_Block *) NIL) ) {
- if (LfsIsNilDiskAddr(smemPtr->blockIndexPtr[blockNum])) {
- bzero(blockPtr->blockAddr, smemPtr->params.blockSize);
- hdrPtr = (LfsStableMemBlockHdr *) blockPtr->blockAddr;
- hdrPtr->magic = LFS_STABLE_MEM_BLOCK_MAGIC;
- hdrPtr->memType = smemPtr->params.memType;
- hdrPtr->blockNum = blockNum;
- dirtied = TRUE;
- } else {
- switch (smemPtr->params.memType) {
- case LFS_DESC_MAP_MOD: {
- LFS_STATS_INC(smemPtr->lfsPtr->stats.desc.descMapBlockMiss);
- break;
- }
- case LFS_SEG_USAGE_MOD: {
- LFS_STATS_INC(smemPtr->lfsPtr->stats.segusage.segUsageBlockMiss);
- break;
- }
- }
- status = LfsReadBytes(smemPtr->lfsPtr,
- smemPtr->blockIndexPtr[blockNum],
- smemPtr->params.blockSize,
- blockPtr->blockAddr);
- #ifdef ERROR_CHECK
- if (smemPtr->params.memType != LFS_SEG_USAGE_MOD) {
- LfsCheckRead(smemPtr->lfsPtr,
- smemPtr->blockIndexPtr[blockNum],
- smemPtr->params.blockSize);
- }
- #endif
- }
-
- if (status != SUCCESS) {
- Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0,
- FSCACHE_DELETE_BLOCK);
- }
- }
- entryPtr->modified = dirtied;
- }
- if (blockPtr != (Fscache_Block *) NIL) {
- #ifdef ERROR_CHECK
- hdrPtr = (LfsStableMemBlockHdr *) blockPtr->blockAddr;
- if ((hdrPtr->magic != LFS_STABLE_MEM_BLOCK_MAGIC) ||
- (hdrPtr->memType != smemPtr->params.memType) ||
- (hdrPtr->blockNum != blockNum)) {
- LfsError(smemPtr->lfsPtr, FAILURE, "Bad LfsStableMemBlockHdr\n");
- }
- #endif /* ERROR_CHECK */
- entryPtr->addr = blockPtr->blockAddr + offset;
- entryPtr->blockNum = blockNum;
- entryPtr->clientData = (ClientData) blockPtr;
- } else {
- status = FS_WOULD_BLOCK;
- }
- return status;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * LfsStableMemRelease --
- *
- * Routine to release a previous fetched stable memory ebtrt,
- *
- * Results:
- * None.
- *
- * Side effects:
- * Many
- *
- *----------------------------------------------------------------------
- */
-
- void
- LfsStableMemRelease(smemPtr, entryPtr, modified)
- LfsStableMem *smemPtr; /* Index description. */
- LfsStableMemEntry *entryPtr; /* Stable memory entry to return. */
- Boolean modified; /* TRUE if block was modified. */
- {
- Fscache_Block *blockPtr;
- time_t timeDirtied;
- int blockNum;
-
- blockPtr = (Fscache_Block *) entryPtr->clientData;
- blockNum = blockPtr->blockNum;
- modified = modified || entryPtr->modified;
- timeDirtied = modified ? -1 : 0;
- Fscache_UnlockBlock(blockPtr, timeDirtied, blockNum,
- smemPtr->params.blockSize, 0);
- entryPtr->addr = (Address)NIL;
- if (modified && !LfsIsNilDiskAddr(smemPtr->blockIndexPtr[blockNum])) {
- /*
- * If the block was modified free the old address up.
- */
- LfsSegUsageFreeBlocks(smemPtr->lfsPtr,
- (int)(smemPtr->params.blockSize), 1,
- (LfsDiskAddr *) smemPtr->blockIndexPtr + blockNum);
-
- }
- return;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * AddBlockToSegment --
- *
- * Add a metadata block to the specified segment.
- *
- * Results:
- * TRUE if segment is full so we couldn't add block.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-
- static Boolean
- AddBlockToSegment(smemPtr, address, blockNum, clientData, segPtr)
- LfsStableMem *smemPtr; /* Index of block. */
- Address address; /* Address of block. */
- int blockNum; /* Block number. */
- ClientData clientData; /* Client data for entry. */
- LfsSeg *segPtr; /* Segment to place data blocks in. */
- {
- int fsBlocks;
- char *summaryPtr;
- LfsSegElement *bufferPtr;
-
- fsBlocks = LfsBytesToBlocks(segPtr->lfsPtr, smemPtr->params.blockSize);
- summaryPtr = LfsSegGrowSummary(segPtr, fsBlocks, sizeof(int));
- if (summaryPtr == (char *)NIL) {
- return TRUE;
- }
- bufferPtr = LfsSegAddDataBuffer(segPtr, fsBlocks, address, clientData);
- *(int *)summaryPtr = blockNum;
- LfsSegSetSummaryPtr(segPtr,summaryPtr + sizeof(int));
- #ifdef ERROR_CHECK
- if (!LfsIsNilDiskAddr(smemPtr->blockIndexPtr[blockNum])) {
- panic("StableMem:AddBlockToSegment disk address not NIL\n");
- }
- #endif
- smemPtr->blockIndexPtr[blockNum] = LfsSegDiskAddress(segPtr, bufferPtr);
- segPtr->activeBytes += smemPtr->params.blockSize;
- if (blockNum >= smemPtr->checkPoint.numBlocks) {
- smemPtr->checkPoint.numBlocks = blockNum + 1;
- }
- return FALSE;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * BlockMatch --
- *
- * Cache backend block type match.
- *
- * Results:
- * TRUE.
- *
- * Side effects:
- *
- * ----------------------------------------------------------------------------
- */
- /*ARGSUSED*/
- static Boolean
- BlockMatch(blockPtr, clientData)
- Fscache_Block *blockPtr;
- ClientData clientData;
- {
- return TRUE;
- }
-
-